iT邦幫忙

2024 iThome 鐵人賽

DAY 3
0
Python

Python 錦囊密技系列 第 3

【Python錦囊㊙️技3】One liners

  • 分享至 

  • xImage
  •  

前言

One liner就是以很短的話語說笑話或打動人心,也有很多人使用一行程式,展現Python的威力,以下筆者就節錄一些One liners,與大家共同品味。

常用功能

  1. 刪除重複值
list1 = [1, 2, 3, 0, 3, 2, 1]
set(list1)

執行結果:{0, 1, 2, 3}

  1. 計算每個值的發生頻率
from collections import Counter

# 測試資料
mylst = [1,1,1,2,2,2,2,3,3,3,3,3,4,4,5,6,6,6]
dict(Counter(mylst))

執行結果:{1: 3, 2: 4, 3: 5, 4: 2, 5: 1, 6: 3}

  1. 兩個值對調(Swap)
    我們再排序時常要將兩個值對調,通常要借用一個變數當緩衝,例如x、y對調,需要借用一個變數temp,如下:
x, y = 100, 200
temp = x
x = y
y = temp
# 測試
x, y

執行結果:(200, 100)

使用python,可以一行取代,不需借個變數temp:

x, y = 100, 200
y, x = x, y
# 測試
x, y

執行結果:(200, 100)

  1. 字串轉陣列
values = list('零一二三四五六七八九')
values

執行結果:['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']

  1. 陣列轉字串
list1 = ['零', '一', '二', '三', '四', '五', '六', '七', '八', '九']
''.join(list1)

執行結果:'零一二三四五六七八九'

  1. 陣列反轉(Reverse)
values = list('零一二三四五六七八九')
values[::-1]

執行結果:['九', '八', '七', '六', '五', '四', '三', '二', '一', '零']

  1. 顯示記憶體用量
import sys

mylst = ['India', 'Paris', 'London', 'Italy', 'Rome', '台灣']
sys.getsizeof(mylst)

執行結果:152

List comprehensive

List comprehensive就是對陣列(List)的每一個元素進行操作,例如要顯示1~100的偶數,正常寫法如下:

for i in range(2, 101, 2):
  print(i)

使用List comprehensive只要一行:

[i for i in range(2, 101, 2)]

執行結果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]

以下衍生一些範例:

  1. 全部偶數加總:
sum([i for i in range(2, 101, 2)])

執行結果:2550

  1. 再加上判斷式:
[i for i in range(2, 101) if i%2 == 0]

與上述程式碼【[i for i in range(2, 101, 2)]】相同。

  1. 顯示1~100的質數(Prime):利用兩個迴圈。
  • 先顯示非質數:可被任一小於要檢查的數值所整除。
# 顯示非質數
set([i for i in range(2, 101) for j in range(2, i) if i%j == 0])

執行結果:set可將重複的元素刪除。

  • 將2~100的list 減掉 非質數的list:
# 兩個set相減可取得差集
set([i for i in range(2, 101)]) - set([i for i in range(2, 101) for j in range(2, i) if i%j == 0])

執行結果:
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97}

List comprehensive + Lambda function

匿名函數(Lambda function)是沒有名字的函數,可簡化函數的撰寫,也可應用在Functional Programming上,將函數當參數傳遞。

  1. 階層(factorial )計算:例如 3! = 1 x 2 x 3。
from functools import reduce
reduce(lambda x, y: x * y, range(1, 4))

reduce是Functional Programming的高階函數(Higher Order Functions),會依函數連乘或連加,另外還有map、filter...等。
執行結果:6。

  1. 再測試6!:
reduce(lambda x, y: x * y, range(1, 6))

執行結果:120。

  1. map會對每個元素執行特定函數,例如取平方:使用map須加list函數才能將map object轉換為 list。
list(map(lambda x: x ** 2, range(1, 6)))

執行結果:[1, 4, 9, 16, 25]。

  1. filter會對每個元素執行特定判斷式,過濾資料,例如篩選偶數。
list(filter(lambda x: x % 2 == 0, range(1, 101)))

執行結果:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100]

更多Functional Programming請看後續的討論。

Dictionary comprehensive + Lambda function

  1. 將1個list組成dictionary:將數字換成大寫。
values = list('零一二三四五六七八九')
dict(enumerate(values))

執行結果:
{0: '零', 1: '一', 2: '二', 3: '三', 4: '四', 5: '五', 6: '六', 7: '七', 8: '八', 9: '九'}

  1. 將2個list組成dictionary:將數字換成大寫。
keys = range(10)
values = list('零一二三四五六七八九')
dict1 = {keys[i]: values[i] for i in range(len(keys))}
# 測試
[dict1[int(i)] for i in list('486')]

執行結果:['四', '八', '六']

  1. 可將執行結果合併:
''.join([dict1[int(i)] for i in list('486')])

執行結果:'四八六'

  1. 依dictionary的value排序。
keys = range(10)
values = list('零一二三四五六七八九')
dict1 = {keys[i]: values[i] for i in range(len(keys))}
# 依dictionary的value排序
sorted([(k, v) for k, v in dict1.items()], key=lambda x: x[1])

執行結果:依大寫的內碼排序。
[(1, '一'), (7, '七'), (3, '三'), (9, '九'), (2, '二'), (5, '五'), (8, '八'), (6, '六'), (4, '四'), (0, '零')]
也可以依key排序dictionary,只要將x[1]改成x[0]即可。

  1. 也可以找出value最大值。
max([(k, v) for k, v in dict1.items()], key=lambda x: x[1])

執行結果:(0, '零'),【零】內碼為最大值。

  1. dictionary key及value互換,以大寫找數字。
{v: k for k, v in dict1.items()} # k, v --> v: k

執行結果:
{'零': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9}

  1. 合併兩個dictionary。
dict1 = {'a': 1, 'b': 2}
dict2 = {'c': 3, 'd': 4}
# 測試
{**dict1, **dict2}

執行結果:
{'a': 1, 'b': 2, 'c': 3, 'd': 4}

One liner + 遞迴(Recursion)

使用 one liner定義費波那契(Fibonacci)數列,它是數列的前2個數字加總會等於下一個數字,且上一個數字除以下一個數字會接近0.618,常用於股票漲跌幅的預測。

def Fib(x): return 1 if x in {0, 1} else Fib(x-1) + Fib(x-2) 
# 測試前10個數列
[Fib(i) for i  in range(1, 11)]

執行結果:
[1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

One liner 創建類別

通常要創建類別(class)如下:

class Employee:   
    def __init__(self, name, age):   
        self.name = name   
        self.age = age  
        
# 測試,實體化物件
michael = Employee("Michael", 25) 
michael.age

執行結果:25

可以一行搞定:

Employee = lambda:None; Employee.name = "Michael"; Employee.age = 25
        
# 測試
type(Employee)

執行結果:<class 'function'>,確實是一個類別,注意,在Jupyter Notebook測試,只會得到function。

結語

使用One liner可以減少程式碼的撰寫,並有效縮小程式碼的行數,缺點是初入門者需花點時間才能理解,系統維護會增加一點難度,可以將One liner包成函數,讓初入門者直接呼叫函數即可。

以上內容係參考下列文章:

  1. 22 Python One-Liners That Every Programmer Should Know
  2. 20 extremely useful single-line Python codes
  3. 10 Cool Python Coding Tricks for Programmers

本系列的程式碼會統一放在GitHub,本篇的程式放在src/3資料夾,歡迎讀者下載測試,如有錯誤或疏漏,請不吝指正。


上一篇
【Python錦囊㊙️技2】Python 很簡單,但要寫的好很不簡單
下一篇
【Python錦囊㊙️技4】函數式程式設計(Functional Programming)
系列文
Python 錦囊密技30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言